package gx

import (
	"slices"
	"sort"
)

type List[T comparable] struct {
	items []T
}

func ListOf[T comparable](items ...T) *List[T] {
	return &List[T]{items: items}
}

// 包含给定的所有值
func (list *List[T]) Contains(values ...T) bool {
	for _, v := range values {
		contains := slices.Contains(list.items, v)
		if !contains {
			return false
		}
	}
	return true
}

// 包含给定值中的任意一个
func (list *List[T]) ContainsAny(values ...T) bool {
	for _, v := range values {
		if slices.Contains(list.items, v) {
			return true
		}
	}
	return false
}

// 元素数量
func (list *List[T]) Len() int {
	return len(list.items)
}

// 在指定索引处插入元素
func (list *List[T]) Insert(index int, values ...T) *List[T] {
	list.items = slices.Insert(list.items, index, values...)
	return list
}

// 删除指定索引处的元素
func (list *List[T]) RemoveAt(index int) *List[T] {
	list.items = append(list.items[:index], list.items[index+1:]...)
	return list
}

// 颠倒序列
func (list *List[T]) Reverse() *List[T] {
	slices.Reverse(list.items)
	return list
}

// 添加元素
func (list *List[T]) Append(value T, unique bool) *List[T] {
	if unique && list.Contains(value) {
		return list
	}
	list.items = append(list.items, value)
	return list
}

// 移除元素
func (list *List[T]) Remove(value T) *List[T] {
	items := []T{}
	for _, item := range list.items {
		if item == value {
			continue
		}
		items = append(items, item)
	}
	list.items = items
	return list
}

// 移除所有元素
func (list *List[T]) Clear() *List[T] {
	list.items = list.items[:0]
	return list
}

// 元素切片
func (list *List[T]) ToSlice() []T {
	return append([]T{}, list.items...)
}

// 第一个元素
func (list *List[T]) First() *T {
	if len(list.items) == 0 {
		return nil
	}
	item := list.items[0]
	return &item
}

// 最后一个元素
func (list *List[T]) Last() *T {
	if len(list.items) == 0 {
		return nil
	}
	item := list.items[len(list.items)-1]
	return &item
}

// 查找符合条件的元素
func (list *List[T]) Find(predicate func(T) bool) *T {
	for _, item := range list.items {
		if predicate(item) {
			return &item
		}
	}
	return nil
}

// 查找所有符合条件的元素
func (list *List[T]) Filter(predicate func(T) bool) *List[T] {
	items := []T{}
	for _, item := range list.items {
		if predicate(item) {
			items = append(items, item)
		}
	}
	result := ListOf(items...)
	return result
}

// 是否存在符合条件的元素
func (list *List[T]) Any(predicate func(T) bool) bool {
	for _, item := range list.items {
		if predicate(item) {
			return true
		}
	}
	return false
}

// 所有元素是否都符合条件
func (list *List[T]) All(predicate func(T) bool) bool {
	for _, item := range list.items {
		if !predicate(item) {
			return false
		}
	}
	return true
}

// 给定值的索引
func (list *List[T]) Index(value T) int {
	return slices.Index(list.items, value)
}

func (list *List[T]) LastIndex(value T) int {
	for i := len(list.items) - 1; i >= 0; i-- {
		if list.items[i] == value {
			return i
		}
	}
	return -1
}

// 获取符合条件的元素索引
func (list *List[T]) FindIndex(predicate func(T) bool) int {
	for i, item := range list.items {
		if predicate(item) {
			return i
		}
	}
	return -1
}

// 反向查找符合条件的元素索引
func (list *List[T]) FindLastIndex(predicate func(T) bool) int {
	for i := len(list.items) - 1; i >= 0; i-- {
		if predicate(list.items[i]) {
			return i
		}
	}
	return -1
}

func (list *List[T]) Sort(less func(T, T) bool) {
	sort.SliceStable(list.items, func(i, j int) bool {
		return less(list.items[i], list.items[j])
	})
}

func (list List[T]) Concat(other List[T]) List[T] {
	return List[T]{items: append(list.items, other.items...)}
}

func (list List[T]) Slice(startIndex, endIndex int) List[T] {
	return List[T]{items: list.items[startIndex:endIndex]}
}

// 分组转换为map
func (list List[T]) GroupBy(keySelector func(T) string) map[string][]T {
	result := make(map[string][]T)
	for _, item := range list.items {
		key := keySelector(item)
		result[key] = append(result[key], item)
	}
	return result
}

// 去重
func (list *List[T]) Unique() *List[T] {
	list.items = slices.Compact(list.items)
	return list
}

// 遍历
func (list *List[T]) ForEach(action func(int, T)) {
	for i, item := range list.items {
		action(i, item)
	}
}

// 转换为字符串切片
func (list *List[T]) MapString(mapper func(int, T) string) []string {
	strValues := []string{}
	for i, item := range list.items {
		strValues = append(strValues, mapper(i, item))
	}
	return strValues
}
